# coding: utf-8
'''
@autor1: João Batista nº5479
@autor2: Luis Cabaço nº5606
@data Inicio: 16/11/2012 - 14:22
@data Fim: 3/12/2012 - 14:38
@obs:
'''

# import de todos os módulos necessários ao 
# controlador 

from sqlalchemy import *

import bd_alchemy as bda
import estatisticas as stats
import criar_csv as escrivao
import graficos as gf
import thread

class memoria_partilhada():
	'''
		Classe memoria_partilhada
			- Esta classe vai ser usada como zona de memoria partilhada entre threads.
	'''

	global bd_lista
	global resultado_estatistica_um
	global resultado_estatistica_dois
	global resultado_estatistica_tres
	global resultado_estatistica_quatro
	global mensagem
	global status

	def set_resultado_estatisticas(self, numero_estatistica, resultado):
		'''
			Metodo para guardar os resultados das estatisticas

			Args:
				numero_estatistica: numero da estatistica a que se refere
				resultado: array com o resultado a guardar
		'''

		global resultado_estatistica_um
		global resultado_estatistica_dois
		global resultado_estatistica_tres
		global resultado_estatistica_quatro

		if numero_estatistica == 1:
			resultado_estatistica_um = resultado
			pass

		elif numero_estatistica == 2:
			resultado_estatistica_dois = resultado
			pass

		elif numero_estatistica == 3:
			resultado_estatistica_tres = resultado
			pass

		elif numero_estatistica == 4:
			resultado_estatistica_quatro = resultado
			pass
		pass

	def get_resultado_estatisticas(self, numero_estatistica):
		'''
			Metodo para carregar os resultados das estatisticas

			Args:
				numero_estatistica: numero da estatistica a que se refere
				
			Returns:
				Devolve um array com os dados da estatistica escolhida
		'''

		global resultado_estatistica_um
		global resultado_estatistica_dois
		global resultado_estatistica_tres
		global resultado_estatistica_quatro

		if numero_estatistica == 1:
			return resultado_estatistica_um

		elif numero_estatistica == 2:
			return resultado_estatistica_dois

		elif numero_estatistica == 3:
			return resultado_estatistica_tres

		elif numero_estatistica == 4:
			return resultado_estatistica_quatro
		pass

	def get_bd(self):
		'''
			Metodo para devolver a base de dados
				
			Returns:
				Devolve array com a base de dados
		'''
		global bd_lista
		return bd_lista

	def set_bd(self, bd):
		'''
			Metodo para guardar a base de dados

			Args:
				bd: lista com a base de dados a guardar	
		'''
		global bd_lista
		bd_lista = bd
		pass

	def get_mensagem(self):
		'''
			Metodo para carregar mensagens necessárias ao programa
				
			Returns:
				Devolve a mensagem
		'''
		global mensagem
		return mensagem

	def set_mensagem(self, texto):
		'''
			Metodo para guardar as mensagens necessárias ao programa

			Args:
				texto: mensagem a guardar
		'''
		global mensagem
		mensagem = texto
		pass

	def get_status(self):
		'''
			Metodo para carregar um estado necessário ao programa
				
			Returns:
				Devolve a mensagem
		'''
		global status
		return status

	def set_status(self, numero):
		'''
			Metodo para guardar um estado necessário ao programa

			Args:
				texto: numero a guardar
		'''
		global status
		status = numero
		pass

class controladorv2():
	'''
		Classe controladorv2
			- Esta classe é a que vai servir de intermediario entre a interface e os restantes modulos
	'''

	def criar_base_dados_thread(self, nome_ficheiro):
		'''
			Metodo para criar a base de dados recorrendo a threads

			Args:
				nome_ficheiro: nome do ficheiro xls que contem os dados necessários ao preenchimento
		'''
		part_mem = memoria_partilhada()
		part_mem.set_status(0)
		thread.start_new_thread(self.criar_base_dados_v3, (nome_ficheiro, ))
		pass

	def carregar_base_dados_thread(self):
		'''
			Metodo para carregar a base de dados recorrendo a threads
		'''
		part_mem = memoria_partilhada()
		part_mem.set_status(0)
		thread.start_new_thread(self.carregar_base_dados_v2, ())
		pass

	def verificar_xls(self):
		'''
			Metodo para verificar a existencia do ficheiro xls necessário ao programa
				
			Returns:
				Devolve o nome do ficheiro
		'''
		criar_bd = bda.BaseDados()
		nome_ficheiro = criar_bd.verificar_ficheiro_xls()
		return nome_ficheiro

	def criar_base_dados_v3(self, nome_ficheiro):
		'''
			Metodo para criar a base de dados usado na versão com threads

			Args:
				nome_ficheiro: nome do ficheiro xls que contem os dados necessários ao preenchimendo da bd
		'''
		part_mem = memoria_partilhada()
		criar_bd = bda.BaseDados()
		engine = create_engine('sqlite:///lp_python_1213.db', echo=False)
		criar_bd.criar_base_dados()
		criar_bd.preencher_base_dados(engine, nome_ficheiro)
		mensagem = 'Base de dados criada com sucesso.\nPor favor carregue a base de dados.'
		part_mem.set_status(11957)
		part_mem.set_mensagem(mensagem)
		pass

	def criar_base_dados_v2(self, nome_ficheiro):
		'''
			Metodo para criar a base de dados usado na versão sem threads

			Args:
				nome_ficheiro: nome do ficheiro xls que contem os dados necessários ao preenchimendo da bd
				
			Returns:
				mensagem: Devolve uma mensagem necessária à execução do programa
		'''
		part_mem = memoria_partilhada()

		criar_bd = bda.BaseDados()
		status = criar_bd.verificar_base_dados()

		#status: estado da existencia do ficheiro da bd
		if status == False:

			if nome_ficheiro == '':

				nome_ficheiro = criar_bd.verificar_ficheiro_xls()

				if nome_ficheiro == False:
					mensagem = 'Ficheiro xls não encontrado'
					part_mem.set_mensagem(mensagem)
					return mensagem

				else:
					criar_bd.criar_base_dados()
					engine = create_engine('sqlite:///lp_python_1213.db', echo=False)
					criar_bd.preencher_base_dados(engine, nome_ficheiro)
					mensagem = 'Base de dados criada com sucesso.\nPor favor carregue a base de dados.'
					part_mem.set_mensagem(mensagem)
					return mensagem
				pass

			else:
				criar_bd.criar_base_dados()
				engine = create_engine('sqlite:///lp_python_1213.db', echo=False)
				criar_bd.preencher_base_dados(engine, nome_ficheiro)

				mensagem = 'Base de dados criada com sucesso.\nPor favor carregue a base de dados.'
				part_mem.set_mensagem(mensagem)
				return mensagem

		else:
			mensagem = 'Base de dados já existe.\nPor favor carregue a base de dados.'
			part_mem.set_mensagem(mensagem)
			return mensagem		
		pass

	def carregar_base_dados_v2(self):
		'''
			Metodo para carregar a base de dados(igual para ambas as versões)
				
			Returns:
				Devolve uma mensagem necessária ao programa
		'''
		part_mem = memoria_partilhada()

		criar_bd = bda.BaseDados()
		status = criar_bd.verificar_base_dados()

		#status: estado da existencia do ficheiro da bd
		if status == True:
			engine = create_engine('sqlite:///lp_python_1213.db', echo=False)
			criar_bd = bda.BaseDados()
			bd = criar_bd.seleccionar_dados(engine)
			part_mem.set_bd(bd)
			mensagem = 'Base de dados carregada com sucesso.'
			part_mem.set_mensagem(mensagem)
			part_mem.set_status(11957)
			return 'Base de dados carregada com sucesso.'

		else:
			mensagem = 'Base de dados não existe.\n Por favor crie uma nova.'
			part_mem.set_mensagem(mensagem)
			part_mem.set_status(11957)
			return 'Base de dados não existe.\n Por favor crie uma nova.'

	def listar_cursos(self):
		'''
			Metodo para ir buscar os cursos que contêm informática 
			e computadores no nome

			Returns:
				cursos: lista com os cursos que têm informática ou computadores
		'''

		part_mem = memoria_partilhada()

		bd_lista = part_mem.get_bd()
		cursos_set = set([])

		# cada linha do ficheiro
		for linha in bd_lista:
			
			# filtro para para os cursos de Informática e Computadores
			if "computadores" in linha[3].encode("utf-8").lower() or "informática" in linha[3].encode("utf-8").lower():

				cursos_set.add(linha[3].encode("utf-8"))
				pass
			pass

		# elimina os items repetidos
		cursos = list(cursos_set)
		cursos.sort()

		del cursos_set

		return cursos

	def listar_niveis_formacao(self):
		'''
			Metodo para devolver os niveis de formação dos cursos que contêm informática 
			ou computadores no nome

			Returns:
				niveis_formacao: lista com os niveis de formação
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		niveis_formacao_set = set([])

		# cada linha do ficheiro
		for linha in bd_lista:
			
			# filtro para para os cursos de Informática e Computadores
			if "computadores" in linha[3].encode("utf-8").lower() or "informática" in linha[3].encode("utf-8").lower():

				niveis_formacao_set.add(linha[2].encode("utf-8"))
				pass
			pass

		# elimina os items repetidos
		niveis_formacao = list(niveis_formacao_set)
		niveis_formacao.sort()

		del niveis_formacao_set

		return niveis_formacao

	def listar_estabelecimento(self):
		'''
			Metodo para devolver os estabelecimentos que tem cursos que contêm informática 
			ou computadores no nome

			Returns:
				estabelecimentos: lista de estabelecimentos
		'''

		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()
		
		estabeleciementos_set = set([])

		# cada linha do ficheiro
		for linha in bd_lista:
			
			# filtro para para os cursos de Informática e Computadores
			if "computadores" in linha[3].encode("utf-8").lower() or "informática" in linha[3].encode("utf-8").lower():
				estabeleciementos_set.add(linha[0].encode("utf-8"))
				pass
			pass

		# elimina os items repetidos
		estabeleciementos = list(estabeleciementos_set)
		estabeleciementos.sort()

		del estabeleciementos_set

		return estabeleciementos

	def calcular_estatistica_um(self, estabelecimento, unidade, curso):
		'''
			Metodo para calcular a primeira estatistica

			Args:
				estabelecimento: string com o estabelecimento pretendido
				unidade: string com a unidade pretendida
				curso: string com o curso pretendido
				
			Returns:
				Devolve um array com os dados da estatistica
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		criar_stats= stats.Estatisticas()

		lista_estatistica_um = criar_stats.primeira_estatistica(bd_lista)

		e1_dados = []

		# caso não seja aplicado nenhum filtro
		if(estabelecimento == '' and unidade == '' and curso == ''):
			cabecalho = ["Estabelecimento", "Unidade Orgânica", "Curso Superior", "Anos"]
			e1_dados.append(cabecalho)
			e1_dados.append(lista_estatistica_um)
			part_mem.set_resultado_estatisticas(1, e1_dados)
			return e1_dados

		#filtrando por estabelecimento
		elif(estabelecimento != '' and unidade == ''):
			cabecalho = ["Unidade Orgânica", "Curso Superior", "Anos"]
			resultado = []
			for linha in lista_estatistica_um:
				resultado_temp = []
				if estabelecimento in linha[0].decode('utf-8'):
					for elemento in xrange(1, len(linha)):
						resultado_temp.append(linha[elemento])
						pass
					resultado.append(resultado_temp)
					del resultado_temp
					pass
				pass

			e1_dados.append(cabecalho)
			e1_dados.append(resultado)
			part_mem.set_resultado_estatisticas(1, e1_dados)

			return e1_dados

		#agora por estabelecimento e unidade
		elif(estabelecimento != '' and unidade != '' and curso == ''):
			cabecalho = ["Curso Superior", "Anos"]
			resultado = []
			for linha in lista_estatistica_um:
				resultado_temp = []
				if estabelecimento in linha[0].decode('utf-8') and unidade in linha[1].decode('utf-8'):
					for elemento in xrange(2, len(linha)):
						resultado_temp.append(linha[elemento])
						pass
					resultado.append(resultado_temp)
					del resultado_temp
					pass
				pass
			
			e1_dados.append(cabecalho)
			e1_dados.append(resultado)
			part_mem.set_resultado_estatisticas(1, e1_dados)

			return e1_dados


		#aplicando os 3 filtros
		elif(estabelecimento != '' and unidade != '' and curso != ''):
			cabecalho = ["Anos"]
			resultado = []
			for linha in lista_estatistica_um:
				resultado_temp = []
				if estabelecimento in linha[0].decode('utf-8') and unidade in linha[1].decode('utf-8') and curso in linha[2].decode('utf-8'):
					for elemento in xrange(3, len(linha)):
						resultado_temp.append(linha[elemento])
						pass
					resultado.append(resultado_temp)
					del resultado_temp
					pass
				pass
			
			e1_dados.append(cabecalho)
			e1_dados.append(resultado)
			part_mem.set_resultado_estatisticas(1, e1_dados)

			return e1_dados

	def calcular_estatistica_dois(self, curso):
		'''
			Metodo para calcular a segunda estatistica

			Args:
				curso: string com o curso pretendido
				
			Returns:
				Devolve um array com os dados da estatistica
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		criar_stats= stats.Estatisticas()
		e2_dados = []

		lista_estatistica_dois= criar_stats.segunda_estatistica(bd_lista)

		#sem filtro
		if(curso == ''):
			cabecalho = ["Curso", "95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02", "02/03",
						 "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]
			
			lista_resultados = []

			for curso in lista_estatistica_dois:
				lista_temp = []
				lista_temp.append(curso.encode("utf-8"))
				for ano in xrange(7, 53, 3):
					lista_temp.append(lista_estatistica_dois[curso][ano])
					pass
				lista_resultados.append(lista_temp)
				del lista_temp
				pass

			e2_dados.append(cabecalho)
			e2_dados.append(lista_resultados)

			part_mem.set_resultado_estatisticas(2, e2_dados)
			return e2_dados

		#escolhendo o curso
		else:
			resultado = []
			cabecalho = ["95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02", "02/03",
						 "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]
			

			lista_resultados = lista_estatistica_dois[curso]
			
			lista_temp=[]
			for ano in xrange(7, 53, 3):
				lista_temp.append(lista_resultados[ano])
				pass

			e2_dados.append(cabecalho)
			e2_dados.append(lista_temp)

			part_mem.set_resultado_estatisticas(2, e2_dados)

			return e2_dados

	def calcular_estatistica_tres(self, nivel):
		'''
			Metodo para calcular a terceira estatistica

			Args:
				nivel: string com o nivel pretendido
				
			Returns:
				Devolve um array com os dados da estatistica
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		criar_stats= stats.Estatisticas()
		e3_dados = []

		lista_estatistica_tres= criar_stats.terceira_quarta_estatistica(bd_lista)

		#sem filtro
		if(nivel == ''):
			cabecalho = ["Nivel de Formação", "95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02",
						 "02/03", "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]


			lista_resultados = []

			for nivel in lista_estatistica_tres:
				lista_temp = []
				lista_temp.append(nivel.encode("utf-8"))
				for ano in xrange(7, 53, 3):
					lista_temp.append(len(lista_estatistica_tres[nivel][ano]))
					pass
				lista_resultados.append(lista_temp)
				del lista_temp
				pass

			e3_dados.append(cabecalho)
			e3_dados.append(lista_resultados)

			part_mem.set_resultado_estatisticas(3, e3_dados)
			return e3_dados

		# com filtro
		else:
			resultado = []
			cabecalho = ["95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02", "02/03",
						 "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]

			lista_resultados = lista_estatistica_tres[nivel]
			
			lista_temp=[]
			for ano in xrange(7, 53, 3):
				lista_temp.append(len(lista_resultados[ano]))
				pass

			e3_dados.append(cabecalho)
			e3_dados.append(lista_temp)

			part_mem.set_resultado_estatisticas(3, e3_dados)

			return e3_dados

	def calcular_estatistica_quatro(self, nivel):
		'''
			Metodo para calcular a quarta estatistica

			Args:
				nivel: string com o nivel pretendido
				
			Returns:
				Devolve um array com os dados da estatistica
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		criar_stats= stats.Estatisticas()
		e4_dados = []

		lista_estatistica_quatro= criar_stats.terceira_quarta_estatistica(bd_lista)

		#sem filtro
		if(nivel == ''):
			cabecalho = ["Nivel de Formação", "95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02",
						 "02/03", "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]

			lista_resultados = []

			for nivel in lista_estatistica_quatro:
				lista_temp = []
				lista_temp.append(nivel.encode("utf-8"))
				for ano in xrange(7, 53, 3):
					lista_temp.append(sum(lista_estatistica_quatro[nivel][ano]))
					pass
				lista_resultados.append(lista_temp)
				del lista_temp
				pass

			e4_dados.append(cabecalho)
			e4_dados.append(lista_resultados)

			part_mem.set_resultado_estatisticas(4, e4_dados)
			return e4_dados

		#com filtro
		else:
			resultado = []
			cabecalho = ["95/96", "96/97", "97/98", "98/99", "99/00", "00/01", "01/02", "02/03",
						 "03/04", "04/05", "05/06", "06/07", "07/08", "08/09", "09/10", "10/11"]

			lista_resultados = lista_estatistica_quatro[nivel]
			
			lista_temp=[]
			for ano in xrange(7, 53, 3):
				lista_temp.append(len(lista_resultados[ano]))
				pass

			e4_dados.append(cabecalho)
			e4_dados.append(lista_temp)

			part_mem.set_resultado_estatisticas(4, e4_dados)

			return e4_dados		

	def estatistica_um_buscar_unidades(self, estabelecimento):
		'''
			Metodo para carregar as unidades da estatistica um consuante os estabelecimentos

			Args:
				estabelecimento: estabelecimento escolhido na interface
				
			Returns:
				Devolve um array com a lista de unidades
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		unidades_set = set([])
		criar_stats= stats.Estatisticas()

		lista_estatistica_um = criar_stats.primeira_estatistica(bd_lista)

		for linha in lista_estatistica_um:
			if estabelecimento.encode('utf-8') in linha[0]:			
				unidades_set.add(linha[1])
				pass
			pass

		lista_unidades = list(unidades_set)
		lista_unidades.sort()

		del unidades_set

		return lista_unidades

	def estatistica_um_buscar_cursos(self, estabelecimento, unidade):
		'''
			Metodo para carregar os cursos da estatistica um consuante os estabelecimentos e unidade

			Args:
				estabelecimento: estabelecimento escolhido na interface
				unidade: unidade escolhida na interface
				
			Returns:
				Devolve um array com a lista de cursos
		'''
		part_mem = memoria_partilhada()
		bd_lista = part_mem.get_bd()

		cursos_set = set([])
		criar_stats= stats.Estatisticas()

		lista_estatistica_um = criar_stats.primeira_estatistica(bd_lista)

		for linha in lista_estatistica_um:
			if estabelecimento.encode('utf-8') in linha[0] and unidade.encode('utf-8') in linha[1]:			
				cursos_set.add(linha[2])
				pass
			pass

		lista_cursos = list(cursos_set)
		lista_cursos.sort()

		del cursos_set

		return lista_cursos

	def criar_csv(self, nome_ficheiro, cabecalho, lista):
		'''
			Metodo para carregar os resultados das estatisticas para um csv

			Args:
				nome_ficheiro: recebido da interface, nome com que o ficheiro vai ser guardado
				cabecalho: recebido da interface, cabeçalho do csv para saber o que são os dados
				lista: recebido da interface, lista com os resultados das estatisticas
				
			Returns:
				Devolve uma mensagem necessária ao programa
		'''
		preencher_csv = escrivao.Criar_csv()
		mensagem = preencher_csv.verificar_ficheiro_csv(nome_ficheiro, cabecalho, lista)
		return mensagem
		
	def criar_grafico(self, tipo_grafico, cabecalho, lista):
		'''
			Metodo para criar gráficos

			Args:
				tipo_grafico: recebido da interface, tipo de gráfico a criar
				cabecalho: recebido da interface, cabeçalho do csv para saber o que são os dados
				lista: recebido da interface, lista com os resultados das estatisticas
		'''
		desenhar_grafico = gf.Criar_grafico()

		if tipo_grafico == 1:
			desenhar_grafico.grafico_barras(cabecalho, lista)
			pass

		if tipo_grafico == 2:
			desenhar_grafico.grafico_tarte(cabecalho, lista)
			pass

	def criar_grafico_threaded(self, tipo_grafico, cabecalho, lista):
		'''
			Metodo para criar gráficos usando threads

			Args:
				tipo_grafico: recebido da interface, tipo de gráfico a criar
				cabecalho: recebido da interface, cabeçalho do csv para saber o que são os dados
				lista: recebido da interface, lista com os resultados das estatisticas
		'''
		thread.start_new_thread(self.criar_grafico, (tipo_grafico, cabecalho, lista, ))
		pass